﻿package com.shengyin.ec.model.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
@Transaction
public class BaseDaoImpl<T> implements BaseDao<T> {

	@Autowired SessionFactory sessionFactory;

	@Autowired
	HibernateTemplate hibernateTemplate;

	// 实体类类型(由构造方法自动赋值)
	Class<T> entityClass;

	// 构造方法，根据实例类自动获取实体类类型
	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		this.entityClass = null;
		Class c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}
	}

	// -------------------- 基本检索、增加、修改、删除操作 --------------------

	// 根据主键获取实体。如果没有相应的实体，返回 null。
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.shengyin.ec.persistence.dao.BaseDao#get(java.io.Serializable)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#get(java.io.Serializable)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#get(java.io.Serializable)
	 */
	@SuppressWarnings( { "hiding", "unchecked" })
	public <T> T get(Serializable id) {
		return (T) hibernateTemplate.get(entityClass, id);
	}
	
	// 根据主键获取实体。如果没有相应的实体，抛出异常。
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#load(java.lang.Long)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#load(java.lang.Long)
	 */
    public T load(Long id) {
        return (T) hibernateTemplate.load(entityClass, id);
    }

    

	// 获取全部实体。
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#loadAll()
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#loadAll()
	 */
	public List<T> loadAll() {
		return (List<T>) hibernateTemplate.loadAll(entityClass);
	}

	// 根据主键获取实体并加锁。如果没有相应的实体，返回 null。
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#getWithLock(java.lang.Long, org.hibernate.LockMode)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#getWithLock(java.lang.Long, org.hibernate.LockMode)
	 */
	public T getWithLock(Long id, LockMode lock) {
		T t = (T) hibernateTemplate.get(entityClass, id, lock);
		if (t != null) {
			this.flush(); // 立即刷新，否则锁不会生效。
		}
		return t;
	}

	// 存储实体到数据库
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#save(T)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#save(T)
	 */
	public void save(T entity) {
		hibernateTemplate.save(entity);
	}

	// saveWithLock()？


	// 增加或更新实体
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#saveOrUpdate(T)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#saveOrUpdate(T)
	 */
	public void saveOrUpdate(T entity) {
		hibernateTemplate.saveOrUpdate(entity);
	}
	

	// 更新实体
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#update(T)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#update(T)
	 */
	public void update(T entity) {
		hibernateTemplate.update(entity);
	}

	// 更新实体并加锁
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#updateWithLock(T, org.hibernate.LockMode)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#updateWithLock(T, org.hibernate.LockMode)
	 */
	public void updateWithLock(T entity, LockMode lock) {
		hibernateTemplate.update(entity, lock);
		this.flush(); // 立即刷新，否则锁不会生效。
	}

	

	// 增加或更新集合中的全部实体
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#saveOrUpdateAll(java.util.Collection)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#saveOrUpdateAll(java.util.Collection)
	 */
	public void saveOrUpdateAll(Collection<T> entities) {
		hibernateTemplate.saveOrUpdateAll(entities);
	}

	// 删除指定的实体
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#delete(T)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#delete(T)
	 */
	public void delete(T entity) {
		hibernateTemplate.delete(entity);
	}

	// 加锁并删除指定的实体
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#deleteWithLock(T, org.hibernate.LockMode)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#deleteWithLock(T, org.hibernate.LockMode)
	 */
    public void deleteWithLock(T entity, LockMode lock) {
    	hibernateTemplate.delete(entity, lock);
        this.flush(); // 立即刷新，否则锁不会生效。
    }

    // 根据主键删除指定实体
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#deleteByKey(java.lang.Long)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#deleteByKey(java.lang.Long)
	 */
    public void deleteByKey(Long id) {
        this.delete(this.load(id));
    }

    // 根据主键加锁并删除指定的实体
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#deleteByKeyWithLock(java.lang.Long, org.hibernate.LockMode)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#deleteByKeyWithLock(java.lang.Long, org.hibernate.LockMode)
	 */
    public void deleteByKeyWithLock(Long id, LockMode lock) {
        this.deleteWithLock(this.load(id), lock);
    }

    // 删除集合中的全部实体
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#deleteAll(java.util.Collection)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#deleteAll(java.util.Collection)
	 */
    public void deleteAll(Collection<T> entities) {
    	hibernateTemplate.deleteAll(entities);
    }

    // -------------------- HSQL ----------------------------------------------

    // 使用HSQL语句直接增加、更新、删除实体
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#bulkUpdate(java.lang.String)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#bulkUpdate(java.lang.String)
	 */
    public int bulkUpdate(String queryString) {
        return hibernateTemplate.bulkUpdate(queryString);
    }

    // 使用带参数的HSQL语句增加、更新、删除实体
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#bulkUpdate(java.lang.String, java.lang.Object[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#bulkUpdate(java.lang.String, java.lang.Object[])
	 */
    public int bulkUpdate(String queryString, Object[] values) {
        return hibernateTemplate.bulkUpdate(queryString, values);
    }

    // 使用HSQL语句检索数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#find(java.lang.String)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#find(java.lang.String)
	 */
    @SuppressWarnings("unchecked")
	public List find(String queryString) {
        return hibernateTemplate.find(queryString);
    }

    // 使用带参数的HSQL语句检索数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#find(java.lang.String, java.lang.Object[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#find(java.lang.String, java.lang.Object[])
	 */
    @SuppressWarnings("unchecked")
	public List find(String queryString, Object[] values) {
        return hibernateTemplate.find(queryString, values);
    }

    // 使用带命名的参数的HSQL语句检索数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findByNamedParam(java.lang.String, java.lang.String[], java.lang.Object[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findByNamedParam(java.lang.String, java.lang.String[], java.lang.Object[])
	 */
    @SuppressWarnings("unchecked")
	public List findByNamedParam(String queryString, String[] paramNames,
            Object[] values) {
        return hibernateTemplate.findByNamedParam(queryString, paramNames,
                values);
    }

    // 使用命名的HSQL语句检索数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findByNamedQuery(java.lang.String)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findByNamedQuery(java.lang.String)
	 */
    @SuppressWarnings("unchecked")
	public List findByNamedQuery(String queryName) {
        return hibernateTemplate.findByNamedQuery(queryName);
    }

    // 使用带参数的命名HSQL语句检索数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findByNamedQuery(java.lang.String, java.lang.Object[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findByNamedQuery(java.lang.String, java.lang.Object[])
	 */
    @SuppressWarnings("unchecked")
	public List findByNamedQuery(String queryName, Object[] values) {
        return hibernateTemplate.findByNamedQuery(queryName, values);
    }

    // 使用带命名参数的命名HSQL语句检索数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findByNamedQueryAndNamedParam(java.lang.String, java.lang.String[], java.lang.Object[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findByNamedQueryAndNamedParam(java.lang.String, java.lang.String[], java.lang.Object[])
	 */
    @SuppressWarnings("unchecked")
	public List findByNamedQueryAndNamedParam(String queryName,
            String[] paramNames, Object[] values) {
        return hibernateTemplate.findByNamedQueryAndNamedParam(queryName,
                paramNames, values);
    }
    
    
    /** 
         * 使用HQL语句进行分页查询操作 
         * offset 第一条记录的索引 
         * pageSize 每页需要显示的记录数 
         * @return 当前页的所有记录 
         */  
        public List findByPage(final String hql, final int offset, final int pageSize){  
            List list = hibernateTemplate.executeFind(new HibernateCallback() {  
                  
                public Object doInHibernate(Session session) throws HibernateException,  
                        SQLException {  
                    List result = session.createQuery(hql).setFirstResult(offset)  
                                    .setMaxResults(pageSize)  
                                   .list();  
                    return result;  
                }  
            });  
            return list;  
        }  

        
        /** 
             * 使用HQL语句进行分页查询操作 
             * value 如果HQL有一个参数需要传入，则value就是传入的参数 
             * offset 第一条记录的索引 
             * pageSize 每页需要显示的记录数 
             * @return 当前页的所有记录 
             */  
            public List findByPage(final String hql, final Object value,  final int offset, final int pageSize){  
        //System.out.println("PageDaoHibernate.findByPage()");  
               List list = hibernateTemplate.executeFind(new HibernateCallback() {  
                      
                    public Object doInHibernate(Session session) throws HibernateException,  
                           SQLException {  
                        List result = session.createQuery(hql).setFirstResult(offset)  
                                        .setParameter(0, value)  
                                       .setMaxResults(pageSize)  
                                        .list();  
                       return result;  
                    }  
                });  
                return list;  
            }  

            
            /** 
                 * 使用HQL语句进行分页查询操作 
                 * values 如果HQL有多个参数需要传入，则values就是传入的参数数组 
                * offset 第一条记录的索引 
               * pageSize 每页需要显示的记录数 
                 * @return 当前页的所有记录 
                */  
                public List findByPage(final String hql, final Object[] values,  final int offset, final int pageSize){  
                   List list = hibernateTemplate.executeFind(new HibernateCallback() {  
                         
                        public Object doInHibernate(Session session) throws HibernateException,  
                                SQLException {  
                            Query query = session.createQuery(hql);  
                            for (int i = 0; i < values.length; i++) {  
                                query.setParameter(i, values[i]);  
                           }  
                            List result = query.setFirstResult(offset)  
                                           .setMaxResults(pageSize)  
                                            .list();  
                            return result;  
                        }  
                    });  
                   return list;  
                }  
             


    // 使用HSQL语句检索数据，返回 Iterator
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#iterate(java.lang.String)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#iterate(java.lang.String)
	 */
    @SuppressWarnings("unchecked")
	public Iterator iterate(String queryString) {
        return hibernateTemplate.iterate(queryString);
    }

    // 使用带参数HSQL语句检索数据，返回 Iterator
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#iterate(java.lang.String, java.lang.Object[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#iterate(java.lang.String, java.lang.Object[])
	 */
    @SuppressWarnings("unchecked")
	public Iterator iterate(String queryString, Object[] values) {
        return hibernateTemplate.iterate(queryString, values);
    }

    // 关闭检索返回的 Iterator
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#closeIterator(java.util.Iterator)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#closeIterator(java.util.Iterator)
	 */
    @SuppressWarnings("unchecked")
	public void closeIterator(Iterator it) {
        hibernateTemplate.closeIterator(it);
    }

    // -------------------------------- Criteria ------------------------------

    // 创建与会话无关的检索标准
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#createDetachedCriteria()
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#createDetachedCriteria()
	 */
    public DetachedCriteria createDetachedCriteria() {
        return DetachedCriteria.forClass(this.entityClass);
    }

    // 创建与会话绑定的检索标准
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#createCriteria()
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#createCriteria()
	 */
    public Criteria createCriteria() {
        return this.createDetachedCriteria().getExecutableCriteria(
                this.getSession());
    }

    // 检索满足标准的数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findByCriteria(org.hibernate.criterion.DetachedCriteria)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findByCriteria(org.hibernate.criterion.DetachedCriteria)
	 */
    @SuppressWarnings("unchecked")
	public List findByCriteria(DetachedCriteria criteria) {
        return hibernateTemplate.findByCriteria(criteria);
    }

    // 检索满足标准的数据，返回指定范围的记录
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findByCriteria(org.hibernate.criterion.DetachedCriteria, int, int)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findByCriteria(org.hibernate.criterion.DetachedCriteria, int, int)
	 */
    @SuppressWarnings("unchecked")
	public List findByCriteria(DetachedCriteria criteria, int firstResult,
            int maxResults) {
        return hibernateTemplate.findByCriteria(criteria, firstResult,
                maxResults);
    }

    // 使用指定的实体及属性检索（满足除主键外属性＝实体值）数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findEqualByEntity(T, java.lang.String[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findEqualByEntity(T, java.lang.String[])
	 */
    @SuppressWarnings("unchecked")
	public List<T> findEqualByEntity(T entity, String[] propertyNames) {
        Criteria criteria = this.createCriteria();
        Example exam = Example.create(entity);
        exam.excludeZeroes();
        String[] defPropertys = sessionFactory.getClassMetadata(
                entityClass).getPropertyNames();
        for (String defProperty : defPropertys) {
            int ii = 0;
            for (ii = 0; ii < propertyNames.length; ++ii) {
                if (defProperty.equals(propertyNames[ii])) {
                    criteria.addOrder(Order.asc(defProperty));
                    break;
                }
            }
            if (ii == propertyNames.length) {
                exam.excludeProperty(defProperty);
            }
        }
        criteria.add(exam);
        return (List<T>) criteria.list();
    }

    // 使用指定的实体及属性检索（满足属性 like 串实体值）数据
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#findLikeByEntity(T, java.lang.String[])
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#findLikeByEntity(T, java.lang.String[])
	 */
    @SuppressWarnings("unchecked")
	public List<T> findLikeByEntity(T entity, String[] propertyNames) {
        Criteria criteria = this.createCriteria();
        for (String property : propertyNames) {
            try {
                Object value = PropertyUtils.getProperty(entity, property);
                if (value instanceof String) {
                    criteria.add(Restrictions.like(property, (String) value,
                            MatchMode.ANYWHERE));
                    criteria.addOrder(Order.asc(property));
                } else {
                    criteria.add(Restrictions.eq(property, value));
                    criteria.addOrder(Order.asc(property));
                }
            } catch (Exception ex) {
                // 忽略无效的检索参考数据。
            }
        }
        return (List<T>) criteria.list();
    }

    // 使用指定的检索标准获取满足标准的记录数
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#getRowCount(org.hibernate.criterion.DetachedCriteria)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#getRowCount(org.hibernate.criterion.DetachedCriteria)
	 */
    @SuppressWarnings("unchecked")
	public Integer getRowCount(DetachedCriteria criteria) {
        criteria.setProjection(Projections.rowCount());
        List list = this.findByCriteria(criteria, 0, 1);
        return (Integer) list.get(0);
    }

    // 使用指定的检索标准检索数据，返回指定统计值(max,min,avg,sum)
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#getStatValue(org.hibernate.criterion.DetachedCriteria, java.lang.String, java.lang.String)
	 */
    /* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#getStatValue(org.hibernate.criterion.DetachedCriteria, java.lang.String, java.lang.String)
	 */
    @SuppressWarnings("unchecked")
	public Object getStatValue(DetachedCriteria criteria, String propertyName,
            String StatName) {
        if (StatName.toLowerCase().equals("max"))
            criteria.setProjection(Projections.max(propertyName));
        else if (StatName.toLowerCase().equals("min"))
            criteria.setProjection(Projections.min(propertyName));
        else if (StatName.toLowerCase().equals("avg"))
            criteria.setProjection(Projections.avg(propertyName));
        else if (StatName.toLowerCase().equals("sum"))
            criteria.setProjection(Projections.sum(propertyName));
        else
            return null;
        List list = this.findByCriteria(criteria, 0, 1);
        return list.get(0);
    }

    
	
	// -------------------------------- Others --------------------------------

	// 加锁指定的实体
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#lock(T, org.hibernate.LockMode)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#lock(T, org.hibernate.LockMode)
	 */
	public void lock(T entity, LockMode lock) {
		hibernateTemplate.lock(entity, lock);
	}

	// 强制初始化指定的实体
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#initialize(java.lang.Object)
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#initialize(java.lang.Object)
	 */
	public void initialize(Object proxy) {
		hibernateTemplate.initialize(proxy);
	}

	// 强制立即更新缓冲数据到数据库（否则仅在事务提交时才更新）
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#flush()
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#flush()
	 */
	public void flush() {
		hibernateTemplate.flush();
	}

	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.dao#getSession()
	 */
	/* (non-Javadoc)
	 * @see com.shengyin.ec.persistence.dao.BaseDao#getSession()
	 */
	public Session getSession(){
		return sessionFactory.openSession();
	}
	
}
